/*
 * @(#)Fractal.java   09/10/11
 * 
 * Copyright (C) 2009 Ecole des Mines d'Ales
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Contact: yulinz88@gmail.com
 */



package fr.ema.arch3d.ref;

import fr.ema.arch3d.ref.controllers.interfaces.AssemblyDescriptorController;
import fr.ema.arch3d.ref.controllers.interfaces.ComponentDescriptorController;
import fr.ema.arch3d.ref.controllers.interfaces.ConnectorController;
import fr.ema.arch3d.ref.controllers.interfaces.ConnectorDescriptorController;
import fr.ema.arch3d.ref.controllers.interfaces.ElementtypeController;
import fr.ema.arch3d.ref.controllers.interfaces.EvolutionController;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.AttributeController;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.LifeCycleController;
import org.objectweb.fractal.api.control.NameController;
import org.objectweb.fractal.api.control.SuperController;
import org.objectweb.fractal.api.factory.Factory;
import org.objectweb.fractal.api.factory.GenericFactory;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.TypeFactory;

import java.util.Map;

//~--- classes ----------------------------------------------------------------

/**
 * Provides static methods to access standard interfaces of Fractal components.
 */
public class Fractal {

    /**
     * Private constructor (uninstantiable class).
     */
    private Fractal() {}

    /**
     * Returns a bootstrap component to create other components. This method
     * just calls the corresponding method of the
     * <tt>org.objectweb.fractal.api.Fractal</tt> class.
     *
     * @return a bootstrap component to create other components.
     * @throws InstantiationException if the bootstrap component cannot be
     *      created.
     */
    public static Component getBootstrapComponent() throws InstantiationException {
        return org.objectweb.fractal.api.Fractal.getBootstrapComponent();
    }

    /**
     * Returns a bootstrap component to create other components. This method
     * creates an instance of the class whose name is associated to the
     * "fractal.provider" key, which much implement the {@link Factory} or
     * {@link GenericFactory} interface, and returns the component instantiated by
     * this factory.
     *
     * @param hints a map which must associate a value to the "fractal.provider"
     *      key, and which may associate a ClassLoader to the "classloader" key.
     *      This class loader will be used to load the bootstrap component.
     * @return a bootstrap component to create other components.
     * @throws InstantiationException if the bootstrap component cannot be
     *      created.
     */
    public static Component getBootstrapComponent(final Map hints) throws InstantiationException {
        String bootTmplClassName = (String) hints.get("fractal.provider");

        if (bootTmplClassName == null) {
            bootTmplClassName = System.getProperty("fractal.provider");
        }

        if (bootTmplClassName == null) {
            throw new InstantiationException("The fractal.provider value is not defined");
        }

        Object bootTmpl;

        try {
            ClassLoader cl = (ClassLoader) hints.get("classloader");

            if (cl == null) {
                cl = new Fractal().getClass().getClassLoader();
            }

            Class bootTmplClass = cl.loadClass(bootTmplClassName);

            bootTmpl = bootTmplClass.newInstance();
        } catch (Exception e) {
            throw new InstantiationException("Cannot find or instantiate the '" + bootTmplClassName
                                             + "' class associated to the fractal.provider key");
        }

        if (bootTmpl instanceof GenericFactory) {
            return ((GenericFactory) bootTmpl).newFcInstance(null, null, hints);
        } else {
            return ((Factory) bootTmpl).newFcInstance();
        }
    }

    /**
     * Returns the {@link AttributeController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link AttributeController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static AttributeController getAttributeController(final Component component)
            throws NoSuchInterfaceException {
        return (AttributeController) component.getFcInterface("attribute-controller");
    }

    /**
     * Returns the {@link BindingController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link BindingController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static BindingController getBindingController(final Component component) throws NoSuchInterfaceException {
        return (BindingController) component.getFcInterface("binding-controller");
    }

    /**
     * Returns the {@link ContentController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link ContentController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static ContentController getContentController(final Component component) throws NoSuchInterfaceException {
        return (ContentController) component.getFcInterface("content-controller");
    }

    /**
     * Returns the {@link SuperController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link SuperController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static SuperController getSuperController(final Component component) throws NoSuchInterfaceException {
        return (SuperController) component.getFcInterface("super-controller");
    }

    /**
     * Returns the {@link NameController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link NameController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static NameController getNameController(final Component component) throws NoSuchInterfaceException {
        return (NameController) component.getFcInterface("name-controller");
    }

    /**
     * Returns the {@link LifeCycleController} interface of the given component.
     *
     * @param component a component.
     * @return the {@link LifeCycleController} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static LifeCycleController getLifeCycleController(final Component component)
            throws NoSuchInterfaceException {
        return (LifeCycleController) component.getFcInterface("lifecycle-controller");
    }

    /**
     * Returns the {@link Factory} interface of the given component.
     *
     * @param component a component.
     * @return the {@link Factory} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static Factory getFactory(final Component component) throws NoSuchInterfaceException {
        return (Factory) component.getFcInterface("factory");
    }

    /**
     * Returns the {@link GenericFactory} interface of the given component.
     *
     * @param component a component.
     * @return the {@link GenericFactory} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static GenericFactory getGenericFactory(final Component component) throws NoSuchInterfaceException {
        return (GenericFactory) component.getFcInterface("generic-factory");
    }

    /**
     * Returns the {@link TypeFactory} interface of the given component.
     *
     * @param component a component.
     * @return the {@link TypeFactory} interface of the given component.
     * @throws NoSuchInterfaceException if there is no such interface.
     */
    public static TypeFactory getTypeFactory(final Component component) throws NoSuchInterfaceException {
        return (TypeFactory) component.getFcInterface("type-factory");
    }

    // ////////////////////connector controller

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static ConnectorController getConnectorController(final Component component)
            throws NoSuchInterfaceException {
        return (ConnectorController) component.getFcInterface("connector-controller");
    }

//  ////////////////////evolution manager controller

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static EvolutionController getEvolutionController(final Component component)
            throws NoSuchInterfaceException {
        return (EvolutionController) component.getFcInterface("evolution-controller");
    }

//  ////////////////////configuration manager controller

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static AssemblyDescriptorController getAssemblyDescriptorController(final Component component)
            throws NoSuchInterfaceException {
        return (AssemblyDescriptorController) component.getFcInterface("assemblydescriptor-controller");
    }

//  ////////////////////element type controller

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static ElementtypeController getElementtypeController(final Component component)
            throws NoSuchInterfaceException {
        return (ElementtypeController) component.getFcInterface("elementtype-controller");
    }

//  ////////////////////component descriptor controller

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static ComponentDescriptorController getComponentDescriptorController(final Component component)
            throws NoSuchInterfaceException {
        return (ComponentDescriptorController) component.getFcInterface("componentdescriptor-controller");
    }

    /**
     * Method description
     *
     * @param component  
     * @return  
     * @throws NoSuchInterfaceException  
     */
    public static ConnectorDescriptorController getConnectorDescriptorController(final Component component)
            throws NoSuchInterfaceException {
        return (ConnectorDescriptorController) component.getFcInterface("connectordescriptor-controller");
    }
}
